local function Swarm() --constructor and class definition at once
	
	local this = {}
	
	--stores objects in swarm
	local swarm = {}
	local swarm_end_pointer = 0
	
	
	--compresses the table that stores the swarm, freeing the indexes
	--taken up by removed objectRefs
	--example:
	--	swarm = {obj1, obj4, nil, obj3, nil, obj4}
	--  swarm_end_pointer = 6
	-- becomes
	--  swarm = {obj1, obj4, obj4, obj3}
	--  swarm_end_pointer = 4
	
	function this:cleanup()
		local last = swarm_end_pointer
		local i = 1
		while i < last
		do
			local si = swarm[i]
			if si and not si.removed
			then
				i = i + 1
			else
				local sl = swarm[last]
				if sl and not sl.removed
				then
					swarm[i] = sl
					swarm[last] = nil
					last = last - 1
					i = i + 1
				else
					swarm[last] = nil
					last = last - 1
				end
			end
		end
		--set last to 0 if the swarm is empty
		local sl = swarm[last]
		if last == 1 and (not sl or sl.removed)
		then
			swarm[last] = nil
			last = 0
		end
		swarm_end_pointer = last
	end
	
	--adds an object to the swarm
	function this:signup(entity)
		swarm_end_pointer = swarm_end_pointer + 1
		swarm[swarm_end_pointer] = entity
		entity.following_stage = math.huge
	end
	
	--removes an object from the swarm
	function this:checkout(entity)
		for i = 0, swarm_end_pointer
		do
			if swarm[i] == entity
			then
				swarm[i] = nil
				return
			end
		end
	end
	
	--applies a function to all members of the swarm
	function this:alert(pos, radius, func)
		local nilvals = 0
		for i = 1, swarm_end_pointer
		do
			local entity = swarm[i]
			if entity and not entity.removed
			then
				local opos = entity.object:get_pos()
				if opos --we need to double check for when the entity is removed
				then
					local distance = vector.distance(pos, opos)
					if distance < radius or radius == 0
					then
						func(entity, distance)
					end
				else --entity has been removed
					nilvals = nilvals + 1
				end
			else
				--count nilvals to check if table should be cleaned
				nilvals = nilvals + 1
			end
		end
		--TODO: there's propably a better multiplier
		if nilvals * 2 > swarm_end_pointer or nilvals > 20
		then
			this:cleanup()
		end
	end
	return this
end










--[[
--Testing stuff

local swarm = Swarm()


for i = 1, 6
do
	swarm:signup(i)
end



local clk = os.clock()


swarm:cleanup()

print((os.clock() - clk) * 1000)
--]]






return Swarm
